package top.scauwlt.utils.threadpool;

import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.sun.org.apache.xpath.internal.operations.Bool;
import lombok.extern.slf4j.Slf4j;

import java.util.Map;
import java.util.concurrent.*;

/**
 * 线程池工厂工具类
 *
 * @Author wmm
 * @Date 2022/7/21 14:26
 */
@Slf4j
public final class ThreadPoolFactoryUtil {
    /**
     * 用来创建一组以 threadNamePrefix 区分的线程池，相同 threadNamePrefix 的线程池看作是为同一业务场景服务
     */
    private static final Map<String, ExecutorService> THREAD_POOLS = new ConcurrentHashMap<>();

    /**
     * 创建一个线程池
     *
     * @param customThreadPoolConfig
     * @param threadNamePrefix
     * @param damon
     * @return ExecutorService
     */
    private static ExecutorService createThreadPool(CustomThreadPoolConfig customThreadPoolConfig, String threadNamePrefix, Boolean damon) {
        ThreadFactory factory = createThreadFactory(threadNamePrefix, damon);
        return new ThreadPoolExecutor(customThreadPoolConfig.getCorePoolSize(), customThreadPoolConfig.getMaximumPoolSize(),
                customThreadPoolConfig.getKeepAliveTime(), customThreadPoolConfig.getTimeUnit(), customThreadPoolConfig.getWorkQueue(), factory);
    }

    /**
     * 创建线程池的参数中的线程工厂，主要是用于设置线程命名！
     *
     * @param threadNamePrefix
     * @param damon
     * @return ThreadFactory
     */
    public static ThreadFactory createThreadFactory(String threadNamePrefix, Boolean damon) {
        if (threadNamePrefix != null) {
            if (damon != null) {
                return new ThreadFactoryBuilder().setNameFormat(threadNamePrefix + "-%d").setDaemon(damon).build();
            } else {
                return new ThreadFactoryBuilder().setNameFormat(threadNamePrefix + "-%d").build();
            }
        }
        return Executors.defaultThreadFactory();
    }

    /**
     * 从Map获取可使用的线程池，没有或不可用则重新创建
     *
     * @param customThreadPoolConfig
     * @param threadNamePrefix
     * @param damon
     * @return
     */
    public static ExecutorService createCustomThreadPoolIfAbsent(CustomThreadPoolConfig customThreadPoolConfig, String threadNamePrefix, Boolean damon) {
        ExecutorService threadPool = THREAD_POOLS.computeIfAbsent(threadNamePrefix, k -> createThreadPool(customThreadPoolConfig, threadNamePrefix, damon));
        if (threadPool.isShutdown() || threadPool.isTerminated()) {
            THREAD_POOLS.remove(threadNamePrefix);
            threadPool = createThreadPool(customThreadPoolConfig, threadNamePrefix, damon);
            THREAD_POOLS.put(threadNamePrefix, threadPool);
        }
        return threadPool;
    }

    public static ExecutorService createCustomThreadPoolIfAbsent(CustomThreadPoolConfig customThreadPoolConfig, String threadNamePrefix) {
        return createCustomThreadPoolIfAbsent(customThreadPoolConfig, threadNamePrefix, false);
    }

    public static ExecutorService createCustomThreadPoolIfAbsent(String threadNamePrefix) {
        return createCustomThreadPoolIfAbsent(new CustomThreadPoolConfig(), threadNamePrefix, false);
    }

    /**
     * 关闭所有线程池
     */
    public static void shutDownAllThreadPool() {
        log.info("call shutDownAllThreadPool Method");
        THREAD_POOLS.entrySet().parallelStream().forEach(entry -> {
            ExecutorService executorService = entry.getValue();
            executorService.shutdown();
            log.info("shut down thread pool [{}] [{}]", entry.getKey(), executorService.isTerminated());
            try {
                executorService.awaitTermination(30, TimeUnit.SECONDS);
            } catch (InterruptedException e) {
                log.error("thread pool never shutdown [{}]", entry.getKey());
                executorService.shutdownNow();
            }
        });
    }

}
